package com.zhuqi.netty.bootstrap;

import com.zhuqi.netty.handler.*;
import com.zhuqi.netty.properties.NettyClientProperties;
import com.zhuqi.protocol.MessageCodecSharable;
import com.zhuqi.protocol.ProtocolFrameDecoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author ZhuQi
 * @Date 2023/1/16 10:38
 * @Version 1.0
 * @Description 客户端
 */
@Component
@Slf4j
public class ChatClient implements ApplicationRunner {

	public static ChannelHandlerContext ctx;


	public static AtomicBoolean logging = new AtomicBoolean(false);

	public static AtomicBoolean exit = new AtomicBoolean(false);

	public static DefaultEventLoopGroup defaultEventLoopGroup;

	public static NioEventLoopGroup nioEventLoopGroup;

	public static String username;

	public static Bootstrap bootstrap;

	@Resource
	private NettyClientProperties nettyClientProperties;

	@Resource
	private BasicHandler basicHandler;

	@Resource
	private LoggingHandler loggingHandler;

	@Resource
	private LogOutHandler logOutHandler;


	@Override
	public void run(ApplicationArguments args){
		log.info("初始化Netty组件。。。");
		 initEventLoopGroup();
		 initBootStrap();
		log.info("启动 NettyClient 客户端");
		 startNettyClient();
	}

	private void initBootStrap() {
		bootstrap = new Bootstrap();
		bootstrap.group(nioEventLoopGroup);
		bootstrap.channel(NioSocketChannel.class);
		// 关闭客户端 Nagle 算法
		bootstrap.option(ChannelOption.TCP_NODELAY, false);
		// tcp 保活
		bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
	}

	private void initEventLoopGroup() {
		nioEventLoopGroup = new NioEventLoopGroup(nettyClientProperties.getBossThreadCount());
		defaultEventLoopGroup = new DefaultEventLoopGroup(nettyClientProperties.getDefaultThreadCount());
	}

	public void startNettyClient() {
		MessageCodecSharable messageCodecSharable = new MessageCodecSharable();
		try {
			bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
				@Override
				protected void initChannel(NioSocketChannel ch) {
					ChannelPipeline pipeline = ch.pipeline();
					pipeline.addLast(new ProtocolFrameDecoder());
					pipeline.addLast(messageCodecSharable);
					pipeline.addLast("logging-handler", loggingHandler);
					pipeline.addLast("logout-handler", logOutHandler);
					pipeline.addLast("basic-handler", basicHandler);
					pipeline.addLast(defaultEventLoopGroup,"chat-response", new MessageResponseHandler());
					pipeline.addLast(defaultEventLoopGroup, "heart-beat", new HeartBeatHandler());
					pipeline.addLast(defaultEventLoopGroup, "heart-response-beat", new HeartBeatResponseHandler());
				}
			});
			ChannelFuture channelFuture = bootstrap.connect(nettyClientProperties.getIp(), nettyClientProperties.getPort());
			Channel channel = channelFuture.sync().channel();
			channel.closeFuture().sync();
		} catch (InterruptedException e) {
            e.printStackTrace();
			log.error("client 发生异常", e);
		} finally {
			// 正常退出才关闭线程池 其他原因进行断线重连
			log.info("连接断开");
            log.info("释放 EventLoopGroup");
            shutdown();
		}
	}

	/**
	 * 关闭 EventLoopGroup
	 */
	public static void shutdown() {
		nioEventLoopGroup.shutdownGracefully();
		defaultEventLoopGroup.shutdownGracefully();
	}

}
